package com.meisen.springboot.init;

import com.meisen.springboot.entity.*;
import com.meisen.springboot.service.ArticleService;
import com.meisen.springboot.service.IpBlackListService;
import com.meisen.springboot.service.IpWhiteListService;
import com.meisen.springboot.service.redis.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 系统初始化时候，初始化缓存Data
 *
 * @author meisen
 * 2018-05-04
 */
@Component
public class InitCacheData implements CommandLineRunner {
    private static final Logger LOGGER = LoggerFactory.getLogger(InitCacheData.class);

    private final ArticleService articleService;
    private final ConfigService configService;
    private final ArticleRedisService articleRedisService;
    private final ArticleTagRedisService articleTagRedisService;
    private final ArticlePublishRedisService articlePublishRedisService;
    private final ArticleVisitRedisService articleVisitRedisService;
    private final ConfigRedisService configRedisService;
    private final IpWhiteListService ipWhiteListService;
    private final IpWhiteListRedisService ipWhiteListRedisService;
    private final IpBlackListService ipBlackListService;
    private final IpBlackListRedisService ipBlackListRedisService;
    // 点赞
    private final ArticleComplimentRedisService articleComplimentRedisService;
    // 归档
    private final ArticleAchieveRedisService articleAchieveRedisService;
    @Autowired
    public InitCacheData(ArticleService articleService,
                         ArticleRedisService articleRedisService,
                         ArticlePublishRedisService articlePublishRedisService,
                         ArticleTagRedisService articleTagRedisService,
                         ArticleVisitRedisService articleVisitRedisService,
                         ConfigRedisService configRedisService,
                         ConfigService configService,
                         IpWhiteListService ipWhiteListService,
                         IpWhiteListRedisService ipWhiteListRedisService,
                         IpBlackListService ipBlackListService,
                         IpBlackListRedisService ipBlackListRedisService, ArticleComplimentRedisService articleComplimentRedisService, ArticleAchieveRedisService articleAchieveRedisService) {
        this.articleService = articleService;
        this.articleRedisService = articleRedisService;
        this.articlePublishRedisService = articlePublishRedisService;
        this.articleTagRedisService = articleTagRedisService;
        this.articleVisitRedisService = articleVisitRedisService;
        this.configRedisService = configRedisService;
        this.configService = configService;
        this.ipWhiteListService = ipWhiteListService;
        this.ipWhiteListRedisService = ipWhiteListRedisService;
        this.ipBlackListService = ipBlackListService;
        this.ipBlackListRedisService = ipBlackListRedisService;
        this.articleComplimentRedisService = articleComplimentRedisService;
        this.articleAchieveRedisService = articleAchieveRedisService;
    }

    @Override
    public void run(String... args) throws Exception {
        clearCache();
        initArticleData();
    }

    /**
     * 清空缓存
     */
    private void clearCache() {
        articleVisitRedisService.emptyZSet();
        articleComplimentRedisService.emptyZSet();
        articleRedisService.emptyHash();
        articlePublishRedisService.emptySet();
        articleTagRedisService.emptyHash();
        articleAchieveRedisService.emptyHash();
        configRedisService.emptyHash();
        ipWhiteListRedisService.emptyHash();
        ipBlackListRedisService.emptyHash();
    }

    /**
     * 初始化文章数据
     */
    private void initArticleData() {
        LOGGER.info("--初始化文章数据开始--");
        // 初始化配置缓存
        List<Config> configs = configService.findAll();
        configs.forEach(config -> configRedisService.put(config.getKey(), config, -1));
        // 初始化文章缓存
        List<Article> articles = articleService.findAll();
        articles.stream()
                .peek(this::cacheData)
                .filter(Article::isPublish)
                .forEach(article -> articlePublishRedisService.sAdd(new String[]{article.getId()}, -1L));
        LOGGER.info("--初始化文章数据结束--");
    }

    /**
     * 缓存数据
     * @param article 文章
     */
    private void cacheData(Article article) {
        articleVisitRedisService.add(article.getId(), article.getVisit());
        articleComplimentRedisService.add(article.getId(), article.getCompliment());
        articleRedisService.put(article.getId(), article, -1);
        cacheAchieveData(article);
        Arrays.stream(article.getTags().split(",")).map(this::replaceSpace).forEach(tag -> {
            if (!articleTagRedisService.isKeyExists(tag)) {
                articleTagRedisService.put(tag, article.getId(), -1);
                return;
            }
            // 当hash中存在该tag的时候，通过','号合并
            String values = articleTagRedisService.get(tag);
            articleTagRedisService.put(tag, values + "," + article.getId(), -1);
        });
        // 白名单数据
        List<IpWhiteList> ipWhiteLists = ipWhiteListService.findAll();
        ipWhiteLists.forEach(ipWhiteList -> ipWhiteListRedisService.put(ipWhiteList.getIp(), ipWhiteList, -1));
        // 黑名单
        List<IpBlackList> ipBlackLists = ipBlackListService.findAll();
        ipBlackLists.forEach(ipBlackList -> ipBlackListRedisService.put(ipBlackList.getIp(), ipBlackList, -1));
    }

    /**
     * 缓存归档文章
     * @param article 文章
     */
    private void cacheAchieveData(Article article) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(article.getDate());
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        AchieveData achieveData = new AchieveData();
        achieveData.setId(article.getId());
        achieveData.setDate(article.getDate());
        achieveData.setTitle(article.getTitle());
        if (!articleAchieveRedisService.isKeyExists(year)) {
            articleAchieveRedisService.put(year, new ArrayList<>(Collections.singleton(achieveData)), -1);
            return;
        }
        // 当hash中存在该year的时候
        List<AchieveData> values = articleAchieveRedisService.get(year);
        if (values.contains(achieveData)) {
            return;
        }
        values.add(achieveData);
        articleAchieveRedisService.put(year, values, -1);
    }

    /**
     * 替换空格
     * 通过占位符的形式开替换
     * @param origin 原始字符串
     * @return 替换后的字符串
     */
    private String replaceSpace(final String origin) {
        return origin.replaceAll(" ", "%s");
    }

}
